/**
 * JT808消息解析器
 * @author: WJ
 */

#include "JTMessage.hpp"
#include "bitByte.hpp"
JTMessage::JTMessage(){

}
JTMessage::~JTMessage(){

}

/**
 * 转义还原，消息头、消息体、校验码中均可能包含转义字符
 * @param data 收到的原始消息
 * @param length 待解码数据长度
 * @param unescapedData 解码后数据
 * @return 解码后数据长度，解码后消息包含：消息头\消息体\校验码
 */
size_t JTMessage::unescape(const unsigned char* data, size_t length,unsigned char* unescapedData) {
    size_t unescapedLength = 0;
    for (size_t i = 0; i < length; i++) {
        if (data[i] == ESCAPE_CHAR && i + 1 < length) {
            if (data[i + 1] == ESCAPE_XOR_1) {
                unescapedData[unescapedLength++] = ESCAPE_CHAR;
                ++i;
            } else if (data[i + 1] == ESCAPE_XOR_2) {
                unescapedData[unescapedLength++] = MESSAGE_START_END_FLAG;
                ++i;
            } else {
                //错误处理：非法的转义序列
                std::cerr << "Invalid escape sequence found!" << std::endl;
                return 0;   //或者可以选择抛出异常
            }
        } else {
            unescapedData[unescapedLength++] = data[i];
        }
    }
    return unescapedLength;
}

size_t JTMessage::escape(const unsigned char* data, size_t length,unsigned char* unescapedData) {
    size_t escapedLength = 0;
    for (size_t i = 0; i < length; i++) {
        if (data[i] == ESCAPE_CHAR) {
            unescapedData[escapedLength++] = ESCAPE_CHAR;
            unescapedData[escapedLength++] = ESCAPE_XOR_1;
        } else if (data[i] == MESSAGE_START_END_FLAG) {
            unescapedData[escapedLength++] = ESCAPE_CHAR;
            unescapedData[escapedLength++] = ESCAPE_XOR_2;
        }else{
            unescapedData[escapedLength++] = data[i];
        }
    }
    return escapedLength;
}

//计算校验和的函数
unsigned char JTMessage::calcCheckSum(const unsigned char* buffer, size_t bufferSize) {
    unsigned char checksum = 0;
    for (size_t i = 0; i < bufferSize; i++) {
        checksum ^= buffer[i]; //对当前校验和与缓冲区中的下一个字节进行异或操作
    }
    return checksum;
}


//解析BCD编码的手机号为十进制字符串
std::string JTMessage::decodeBCDPhoneNumber(const uint8_t bcdPhone[10],bool removePreZero) {
    std::string phoneNumber;
    for (size_t i = 0; i < 10; ++i) {
        phoneNumber += ((bcdPhone[i] & 0xf0) >> 4) + '0'; //取高位并转换为字符
        phoneNumber += (bcdPhone[i] & 0x0f) + '0';       //取低位并转换为字符
    }
    if(removePreZero){
        //去除前导零
        size_t nonZeroPos = phoneNumber.find_first_not_of('0');
        if (nonZeroPos != std::string::npos) {
            phoneNumber = phoneNumber.substr(nonZeroPos);
        }
    }
    return phoneNumber;
}

//解析JT808消息头
bool JTMessage::parseHeader(const unsigned char* buffer, size_t bufferSize, JT808Header& header) {
    if (bufferSize < HEADER_MIN_LENGTH) {
        std::cerr << "Buffer too small to contain a minimal JT808 header." << std::endl;
        return false;
    }

    //大端字节序读取
    header.id = (buffer[0] << 8) | buffer[1];
    header.bprops = (buffer[2] << 8) | buffer[3];
    header.version = buffer[4];
    
    //BCD解码手机号
    for(int i = 0; i < 10; ++i) {
        header.phoneNo[i] = buffer[5 + i];
    }
    
    header.seq = (buffer[15] << 24) | (buffer[14] << 16) | (buffer[13] << 8) | buffer[12];

    //解析消息体属性
    header.bodyLength = header.bprops & LENGTH_MASK;     //消息体长度
    header.isEncrypted = (header.bprops   >> 10) & 0x01; //加密标识
    header.isPacketSplit = (header.bprops >> 13) & 0x01; //分包标识，1表示是分包消息，0表示整包消息
    header.versionFlag = (header.bprops   >> 14) & 0x01;     

    //判断是否有分包信息
    if(header.isPacketSplit && bufferSize<HEADER_MAX_LENGTH) {
        std::cerr << "This message is packeted, but has no pack info." << std::endl;
        return false;
    }
    if(header.isPacketSplit) {
        header.packsum = (buffer[17] << 8) | buffer[16];
        header.packseq = (buffer[19] << 8) | buffer[18];
    }
    return true;
}

/**
 * 解析JT808消息
 * @param buffer 消息缓冲区
 * @param len 消息长度
 * @param header 解析输出消息头
 * @param outbuffer 解析输出缓冲区，去掉了前后标识位，完成解转义，包含消息头、消息体、校验码
 * @return outbuffer的长度
 * @note
 */
size_t JTMessage::parse(const unsigned char* buffer,int len,JT808Header& header,unsigned char* outbuffer){
    if(len < MESSAGE_MIN_LENGTH){
        std::cerr << "Message is too short " << len << std::endl;
        return 0;
    }
    if(buffer[0] != MESSAGE_START_END_FLAG || buffer[len-1] != MESSAGE_START_END_FLAG){
        std::cerr << "Invalid Message!" << std::endl;
        return 0;
    }

    //解码，先去掉前后标识位，解码后数据包含消息头、消息体、校验码
    size_t outlen = unescape(buffer+1,len-2,outbuffer);
    //解码后去掉前后端标识符，所以长度减2
    if(outlen<MESSAGE_MIN_LENGTH-2){
        std::cerr << "Unescaped Message is too short  " << outlen << std::endl;
        return 0;
    }
    
    //buffer的最后一位是校验码
    unsigned char checksum = calcCheckSum(outbuffer,outlen-1);
    if(checksum!=outbuffer[outlen-1]){
        std::cerr << "Message check sum error!" << (int)checksum << ":" << (int)outbuffer[outlen-1] << std::endl;
        return 0;
    }
    
    if(!parseHeader(outbuffer,outlen-1,header)){
        std::cerr << "Parse header error!" << std::endl;
        return 0;
    }

    //判断消息长度是否与消息体长度一致
    if(header.isPacketSplit && header.bodyLength!=outlen-1-HEADER_MAX_LENGTH ){
        std::cerr << "Message body length is incorrect! require:" << header.bodyLength << " actual:" << outlen-1-HEADER_MAX_LENGTH << std::endl;
        return 0;
    }else if(!header.isPacketSplit && header.bodyLength!=outlen-1-HEADER_MIN_LENGTH){
        std::cerr << "Message body length is incorrect! require:" << header.bodyLength << " actual:" << outlen-1-HEADER_MIN_LENGTH << std::endl;
        return 0;
    }

    return outlen;
}

/**
 * 调试代码，打印消息头
 * @param header 消息头
 */
void JTMessage::printHeader(JT808Header& header) {
    std::cout << "Message ID: " << header.id << std::endl;
    std::cout << "Message Body Props: " << std::bitset<16>(header.bprops) << std::endl;
    std::cout << "Protocol Version: " << static_cast<int>(header.version) << std::endl;
    std::cout << "Phone Number: " << decodeBCDPhoneNumber(header.phoneNo) << std::endl;
    std::cout << "Sequence No: " << header.seq << std::endl;
    std::cout << "Message Body Length: " << header.bodyLength << std::endl;
    std::cout << "Encrypted: " << (header.isEncrypted ? "Yes" : "No") << std::endl;
    std::cout << "Packet Split: " << (header.isPacketSplit ? "Yes" : "No") << std::endl;
    std::cout << "Version Flag: " << (header.versionFlag ? "Yes" : "No") << std::endl;
    if(header.isPacketSplit){
        std::cout << "Packet Count: " << header.packsum << std::endl;
        std::cout << "Packet Seq: " << header.packseq << std::endl;
    }
}

/**
 * 根据请求的消息头，生成响应消息头
 * 暂不用，大部分消息可以直接使用终端请求的消息头
 */
void   JTMessage::makeResponseHeader(const JT808Header& header, JT808Header& outheader,uint16_t bodyLen,uint16_t seq,uint16_t packsum,uint16_t packseq){
    memcpy(&outheader,&header,sizeof(JT808Header));
    CmdID id = (CmdID)header.id;
    switch (id)
    {
    case CmdID::Register:
        outheader.id = static_cast<uint16_t>(CmdID::RegisterResp);
        outheader.bodyLength = bodyLen;
        break;

    default:
        outheader.id = static_cast<uint16_t>(CmdID::PlatformReply);
        outheader.bodyLength = 5;
        break;
    }
}

/**
 * 解析终端注册消息
 * @param buffer 消息体缓冲区
 * @param bodySize 消息体长度
 * @param clientInfo 解析输出终端注册信息
 * @return 解析成功返回true
 */
bool JTMessage::parseClientInfo(const unsigned char* buffer, size_t bodySize, ClientInfo& clientInfo){
    if(bodySize < REGISTER_MIN_LENGTH){
        std::cerr << "Buffer too small to contain a minimal JT808 client info." << std::endl;
        return false;
    }
    //从body中解析出clientInfo
    clientInfo.province = (buffer[0] << 8) | buffer[1];
    clientInfo.city = (buffer[2] << 8) | buffer[3];

    //解析制造商ID
    memcpy(clientInfo.producerId, buffer + 4, 11);
    clientInfo.producerId[11] = '\0'; //确保字符串结束

    //解析终端型号
    memcpy(clientInfo.model, buffer + 15, 30);
    clientInfo.model[30] = '\0';

    //解析终端ID
    memcpy(clientInfo.id, buffer + 45, 30);
    clientInfo.id[30] = '\0';

    //解析车身颜色
    clientInfo.color = buffer[75];

    //计算车牌的实际长度，注意这里简化处理，假设车牌信息紧跟在结构体固定部分之后
    size_t chepaiLength = bodySize - 76; //+1是因为结构体中未直接定义车牌长度字段
    if (chepaiLength > sizeof(clientInfo.chepai)) {
        std::cerr << "uffer indicates a longer chepai than can be stored in the structure" << std::endl;
        return false;
    }
    memcpy(clientInfo.chepai, buffer + 76, chepaiLength);
    clientInfo.chepai[chepaiLength] = '\0'; //确保字符串结束
    return true;
}

/**
 * 调试客户端信息
 */
void JTMessage::printClientInfo(ClientInfo& clientInfo){
    std::cout << "Province: " << clientInfo.province << std::endl;
    std::cout << "City: " << clientInfo.city << std::endl;
    std::cout << "Producer ID: " << clientInfo.producerId << std::endl;
    std::cout << "Model: " << clientInfo.model << std::endl;
    std::cout << "ID: " << clientInfo.id << std::endl;
    std::cout << "Color: " << clientInfo.color << std::endl;
    std::cout << "Chepai: " << clientInfo.chepai << std::endl;
}
/**
 * 打包JT808消息
 * @param header 消息头，如果使用终端请求的消息头，注意修改其中元素使与实际发送一致
 * @param body 消息体，如果没有消息体，body传NULL，bodySize传0
 * @param bodySize 消息体长度
 * @param outputBuffer 输出缓冲区
 * @return 打包后的消息长度
 */
size_t JTMessage::pack(const JT808Header& header, const unsigned char* body, uint16_t bodySize, unsigned char* outputBuffer) {
    size_t offset = 0;
    unsigned char tempBuffer[MESSAGE_MAX_LENGTH];

    //消息ID
    outputBuffer[offset++] = (header.id >> 8) & 0xFF;
    outputBuffer[offset++] = header.id & 0xFF;

    //消息体属性构造
    uint16_t bprops = (bodySize & 0x03FF) |
                      (header.isEncrypted ? 0x0400 : 0) |
                      (header.isPacketSplit ? 0x0020 : 0) |
                      (header.versionFlag << 14);

    //消息体属性
    outputBuffer[offset++] = (bprops >> 8) & 0xFF;
    outputBuffer[offset++] = bprops & 0xFF;

    //协议版本号
    outputBuffer[offset++] = header.version;

    //BCD编码的手机号
    memcpy(outputBuffer + offset, header.phoneNo, 10);
    offset += 10;

    //消息流水号
    outputBuffer[offset++] = (header.seq >> 8) & 0xFF;
    outputBuffer[offset++] = header.seq & 0xFF;

    //根据分包标识添加packsum和packseq
    if (header.isPacketSplit) {
        outputBuffer[offset++] = (header.packsum >> 8) & 0xFF;
        outputBuffer[offset++] = header.packsum & 0xFF;
        outputBuffer[offset++] = (header.packseq >> 8) & 0xFF;
        outputBuffer[offset++] = header.packseq & 0xFF;
    }

    //消息体
    if (bodySize > 0 && body != nullptr) {
        memcpy(outputBuffer + offset, body, bodySize);
        offset += bodySize;
    }
    //校验码
    outputBuffer[offset] = calcCheckSum(outputBuffer, offset);
    offset++;
    //对outputBuffer进行转义处理
    tempBuffer[0] = MESSAGE_START_END_FLAG;
    size_t escapedLen = escape(outputBuffer, offset, tempBuffer+1);
    tempBuffer[escapedLen+1] = MESSAGE_START_END_FLAG;

    memcpy(outputBuffer, tempBuffer, escapedLen+2);
    return escapedLen+2;
}


/**
 * 封装通用应答消息
 * @param header 消息头
 * @param result 结果码
 * @param CmdID  终端请求的命令ID
 * @param outputBuffer 输出缓冲区
 * @return 封装后的消息长度
 */
size_t JTMessage::commonRespose(const JT808Header& header,uint8_t result, uint16_t CmdID, unsigned char* outputBuffer){
    unsigned char body[5];
    BitByte::packWORD(body,  header.seq);
    BitByte::packWORD(body+2,CmdID);
    body[4] = result;
    return pack(header,body,5,outputBuffer);
}

/**
 * 注册应答消息
 * authCode长度应限制在16字节内
 */
size_t JTMessage::registerRespose(const JT808Header& header,uint8_t result, const unsigned char* authCode,size_t codeLen, unsigned char* outputBuffer){
    size_t bodyLen = 3+codeLen;
    unsigned char body[32];
    BitByte::packWORD(body,header.seq);
    body[2] = result;
    memcpy(body+3,authCode,codeLen);
    return pack(header,body,bodyLen,outputBuffer);
}
